/*
* Copyright (c) 2007 acmesystems.it - john@acmesystems.it
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
*
* Feedback, Bugs...  info@acmesystems.it 
*
*/ 

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

#define IOCTL_SD_CLS	 		0x01
#define IOCTL_SD_INIT			0x02
#define IOCTL_SD_TEXT			0x03
#define IOCTL_SD_TEXT2			0x04
#define IOCTL_SD_SCROLL			0x05
#define IOCTL_SD_TEST			0x06
#define IOCTL_SD_IMAGE			0x07

#define DEVNAME "/dev/lcd"

#define CHECK_OPEN { 						\
			if(!fd_dev){				\
				if(ssd1303_open() == -1){	\
					return 1;		\
				}				\
			}					\
		    }

static int fd_dev = 0;

int ssd1303_open(void) {
	fd_dev = open("/dev/lcd", O_RDWR);
	if (fd_dev <= 0) {
		printf("lcd: open error on /dev/lcd\n");
		return -1;
	}
	return 0;	
}

void ssd1303_close(void) {
	close(fd_dev);
}

int ssd1303_init(void) {
	CHECK_OPEN;
	ioctl(fd_dev, IOCTL_SD_INIT, 0);
	return 0;
}

int ssd1303_test(void) {
	CHECK_OPEN;
	ioctl(fd_dev, IOCTL_SD_TEST, 0);
	return 0;
}

int ssd1303_cls(void){
	CHECK_OPEN;
	ioctl(fd_dev, IOCTL_SD_CLS, 0);
	return 0;
}

#define MAX_TEXT1	256
int ssd1303_text1(unsigned char x, unsigned char y, unsigned char *fmt, ...){
	CHECK_OPEN;
	char p[MAX_TEXT1];	
	va_list ap;
	int n;
	va_start(ap, fmt);
	if(vsnprintf (&p[2], MAX_TEXT1 - 2, fmt, ap) < 1){
		return 1;
	};
	va_end(ap);
	p[0] = x;
	p[1] = y;
	ioctl(fd_dev, IOCTL_SD_TEXT, p);
	return 0;
}

int ssd1303_text2(unsigned char x1, unsigned char x2, unsigned char y, unsigned char *text1, unsigned char *text2, unsigned char offset, unsigned char mask){
	CHECK_OPEN;
	char p[MAX_TEXT1*2];
	strcpy(&p[5], text1);
	strcpy(&p[260], text2);
	p[0] = x1;
	p[1] = y;
	p[2] = x2;
	p[3] = mask;
	p[4] = offset;
	ioctl(fd_dev, IOCTL_SD_TEXT2, p);
	return 0;
}

static unsigned char scroll_text[1024][64];
static unsigned char line;
static unsigned char i, j, k, l;
static unsigned int line_count;

int ssd1303_scroll_setup(unsigned char *data, unsigned int count){
	i = 0;
	j = 0;	
	k = 0;
	l = 0;
	line = 0;
	line_count = count;	
	ssd1303_cls();
	memcpy(scroll_text, data, 64*1024);
	for(i = 0; i < 8; i++){
		ssd1303_text1(0, i, scroll_text[i]);
	}
	i = 0;
}

int ssd1303_scroll_loop(void){
	ssd1303_text2(0, 0, l%8, &scroll_text[(line+8)%line_count][0], &scroll_text[line%line_count][0], i, k);
	if(k == 0xff){
		k = 0x0;
		j = 0;
		l++;
		line++;
	} 
	k += (1<<j);
	j++;
	i++;
}

int ssd1303_image(unsigned char x, unsigned char y, 
		unsigned char cx, unsigned char cy,
		unsigned scroll, unsigned char *data){
	unsigned char d[1024+5];
	CHECK_OPEN;
	memcpy(&d[5], data, cx * cy);
	d[0] = x;
	d[1] = y;
	d[2] = cx;
	d[3] = cy;
	d[4] = scroll;
	ioctl(fd_dev, IOCTL_SD_IMAGE, d);
	printf("sending image to kernel %d %d %d %d\n", d[0], d[1], d[2], d[3]);
}
